#pragma once

#include "Sock.hpp"
#include "Protocol.hpp"
#include <pthread.h>
#include <functional>

namespace tcpserver_ns
{
    using namespace protocol_ns;
    class TcpServer;
    using func_t = std::function<Response(const Request &)>;
    // 线程数据
    struct ThreadData
    {
        ThreadData(int sock, std::string &ip, uint16_t &port, TcpServer *tp)
            : _sock(sock), _ip(ip), _port(port), _tsvrp(tp)
        {
        }

        int _sock;
        std::string _ip;
        uint16_t _port;
        TcpServer *_tsvrp;
    };

    class TcpServer
    {
    public:
        TcpServer(func_t func, uint16_t &port)
            : _port(port), _func(func)
        {
        }

        void InitServer()
        {
            // 1.初始化服务器
            _listensock.SocKet();
            _listensock.Bind(_port);
            _listensock.Listen();
            // 初始化完成
            logMessage(Info, "init server done, listensock: %d", _listensock.Fd());
        }

        void Start()
        {
            while (1)
            {
                std::string clientip;
                uint16_t clientport;
                int sock = _listensock.Accept(&clientip, &clientport);
                if (sock == -1)
                    // 没有连接，继续接收
                    continue;
                // 接受成功
                logMessage(Debug, "get a new client, client info : [%s:%d]", clientip.c_str(), clientport);

                // 开始对数据进行处理---这里使用线程的方式进行任务处理
                pthread_t td;
                ThreadData t(sock, clientip, clientport, this);
                pthread_create(&td, nullptr, threadRun, &t);
            }
        }

        static void *threadRun(void *args)
        {
            ThreadData *td = static_cast<ThreadData *>(args);
            td->_tsvrp->ServiceIO(td->_sock, td->_ip, td->_port);
            delete td;
            return nullptr;
        }

        // 多线程调用
        void ServiceIO(int sock, const std::string &ip, const uint16_t &port)
        {
            std::string inbuffer;
            while (1)
            {
                //你怎么保证你读到了一个完整的字符串报文？"7"\r\n""10 + 20"\r\n


                // 1. 接受———read/recv - 如何正确的读，继续设计协议!!!
                // 我们进行一直循环读取，边读取，边检测，测试
                char buffer[1024];
                ssize_t s = recv(sock, buffer, sizeof(buffer), 0); // 和read差不多,最后一个参数设置为0即可

                // 2.对读取到的string进行反序列化
                Request req;
                req.Deserialize(buffer);

                // 3.反序列化完成之后，就能得到正确的客户端发送的数据，进而对数据进行处理
                // 处理任务
                Response res = _func(req); // 回调任务处理---加减乘除运算

                // 4.任务处理完成之后，给客户端发送响应,注意要先序列化响应信息!!!!
                // 序列化
                std::string send_string;
                res.Serialize(&send_string);

                // 添加报头
                send_string = AddHeader(send_string);

                // 发送
                send(sock, send_string.c_str(), send_string.size(), 0);
            }
        }

        ~TcpServer()
        {
        }

    private:
        Sock _listensock;
        uint16_t _port;
        func_t _func;
    };
}